using System;
using Ext;
using Ext.data;
using Ext.form;
using ScriptFX;

namespace PageScripts {
    public class ProductDetailsForm : Ext.util.Observable {
        private Form _form;
        private LayoutDialog _dialog;
        private FormMode _mode;
        private Record _currentRecord;
        private ProductsPage _productsPage;

        public ProductDetailsForm(ProductsPage page) {
            _productsPage = page;
            addEvents(new Dictionary(
                "inserted", true,
                "updated", true
            ));
        }

        public void Show(FormMode mode, Element el, Record rec) {
            _mode = mode;
            if (Script.IsNullOrUndefined(_dialog)) Init();
            if (_dialog.isVisible()) _dialog.hide(null);

            if (_mode == FormMode.Update) {
                if (!Script.IsNullOrUndefined(rec)) {
                    _form.loadRecord(rec);
                    _form.findField("hSupplierID").setValue(rec.get("SupplierID"));
                    _form.findField("hCategoryID").setValue(rec.get("CategoryID"));
                    _currentRecord = rec;
                } else {
                    MessageBox.alert("Select a Category first ...", "please choose a category to update from the list.", null, null);
                    return;
                }
            } else {
                _currentRecord = null;
                _form.reset();
            }

            _dialog.show(el);
            _dialog.focus();
        }

        public void Init() {
            Script.Eval("Ext.form.Field.prototype.msgTarget = 'side'");
            Script.Eval("Ext.form.Field.prototype.focusClass = 'text-field-focus'");
            Script.Eval("Ext.form.Field.prototype.invalidClass = 'text-field-invalid'");

            TextField name = new TextField(new Dictionary("fieldLabel", "Name", "name", "ProductName", "allowBlank", false));
            ComboBox supplier = new ComboBox(new Dictionary(
                "fieldLabel", "Supplier",
                "name", "SupplierID",
                "hiddenName", "hSupplierID",
                "allowBlank", false, 
                "editable", false,
                "store", _productsPage.GetSuppliersStore(), 
                "displayField", "CompanyName",
                "valueField", "SupplierID",
                "typeAhead", false,
                "triggerAction", "all",
                "emptyText", "Select a Supplier ...",
                "mode", "local",
                "selectOnFocus", true
            ));
            ComboBox category = new ComboBox(new Dictionary(
                "fieldLabel", "Category",
                "name", "CategoryID",
                "hiddenName", "hCategoryID",
                "allowBlank", false,
                "editable", false,
                "store", _productsPage.GetCategoriesStore(),
                "displayField", "CategoryName",
                "valueField", "CategoryID",
                "typeAhead", false,
                "triggerAction", "all",
                "emptyText", "Select a Category ...",
                "mode", "local",
                "selectOnFocus", true
            ));
            TextField quantityPerUnit = new TextField(new Dictionary("fieldLabel", "Quantity Per Unit", "name", "QuantityPerUnit", "allowBlank", false));
            NumberField unitPrice = new NumberField(new Dictionary("fieldLabel", "Unit Price", "name", "UnitPrice", "allowBlank", false, "minvalue", 0));
            NumberField unitsInStock = new NumberField(new Dictionary("fieldLabel", "Units In Stock", "name", "UnitsInStock", "allowBlank", false));
            NumberField unitsOnOrder = new NumberField(new Dictionary("fieldLabel", "Units On Order", "name", "UnitsOnOrder", "allowBlank", false));
            NumberField reorderLevel = new NumberField(new Dictionary("fieldLabel", "Reorder Level", "name", "ReorderLevel", "allowBlank", false));
            Checkbox discontinued = new Checkbox(new Dictionary("fieldLabel", "Discontinued", "name", "Discontinued"));

            _form = new Form(new Dictionary(
                "labelAlign", "left",
                "url", "DataHandler.aspx"
            ));
            _form.column(new Dictionary(
                "width", 425,
                "labelWidth", 120,
                "style", "margin-left:8px;margin-top:8px"
            ));
            _form.fieldset(new Dictionary("id", "productForm", "legend", "Product Details"), name, supplier, category, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued);
            _form.applyIfToFields(new Dictionary("width", 255));
            _form.render("product-edit-form");

            _dialog = new LayoutDialog("product-edit-dialog", new Dictionary(
                "modal", false,
                "autoTabs", true,
                "proxyDrag", true,
                "width", 470,
                "height", 350,
                "shadow", true,
                "center", new Dictionary("autoScroll", true)
            ));
            _dialog.addButton("Save", new AnonymousDelegate(SaveData), this);
            _dialog.addButton("Cancel", new AnonymousDelegate(delegate() { _dialog.hide(null); }), _dialog);
            _dialog.addKeyListener(27, new AnonymousDelegate(delegate() { _dialog.hide(null); }), _dialog);

            BorderLayout layout = _dialog.getLayout();
            layout.beginUpdate();
            layout.add("center", new ContentPanel("product-edit-layout", new Dictionary("title", "Insert Product"), null));
            layout.endUpdate(false);
        }

        private void SaveData() {
            if (_mode == FormMode.Insert) {
                InsertProduct();
            } else if (_mode == FormMode.Update) {
                UpdateProduct();
            }
        }

        private void InsertProduct() {
            if (!_form.isValid()) {
                MessageBox.alert("Invalid Information", "Please correct the invalid fields", null, null);
                return;
            }
            _form.submit(new Dictionary(
                "waitMsg", "Creating New Product ...",
                "reset", true,
                "params", new Dictionary("action", "InsertProduct"),
                "scope", this,
                "failure", new FormSubmitDelegate(delegate(Form form, Action action) {
                    MessageBox.alert("Error!", "There were errors saving this basket. <br />Please correct the errors and try again.", null, null);
                    fireEvent("inserted", this, false);
                }),
                "success", new FormSubmitDelegate(delegate(Form form, Action action) {
                    _dialog.hide(null);
                    fireEvent("inserted", this, true);
                })
            ));
        }

        private void UpdateProduct() {
            if (!_form.isValid()) {
                MessageBox.alert("Invalid Information", "<br />Please correct the invalid fields<br />", null, null);
                return;
            }
            _form.submit(new Dictionary(
                "waitMsg", "Saving Product ...",
                "reset", false,
                "params", new Dictionary("action", "UpdateProduct", "ProductID", _currentRecord.get("ProductID")),
                "scope", this,
                "failure", new FormSubmitDelegate(delegate(Form form, Action action) {
                    MessageBox.alert("Error!", "There were errors saving this basket. <br />Please correct the errors and try again.", null, null);
                    fireEvent("updated", this, false, null);
                }),
                "success", new FormSubmitDelegate(delegate(Form form, Action action) {
                    _dialog.hide(null);
                    Dictionary newValues = new Dictionary(
                        "ProductID", _currentRecord.get("ProductID"),
                        "ProductName", _form.findField("ProductName").getValue(),
                        "SupplierID", _form.findField("hSupplierID").getValue(),
                        "SupplierName", _productsPage.GetSuppliersStore().getById((string)_form.findField("hSupplierID").getValue()).get("CompanyName"),
                        "CategoryID", _form.findField("hCategoryID").getValue(),
                        "CategoryName", _productsPage.GetCategoriesStore().getById((string)_form.findField("hCategoryID").getValue()).get("CategoryName"),
                        "QuantityPerUnit", _form.findField("QuantityPerUnit").getValue(),
                        "UnitPrice", _form.findField("UnitPrice").getValue(),
                        "UnitsInStock", _form.findField("UnitsInStock").getValue(),
                        "UnitsOnOrder", _form.findField("UnitsOnOrder").getValue(),
                        "ReorderLevel", _form.findField("ReorderLevel").getValue(),
                        "Discontinued", _form.findField("Discontinued").getValue()
                    );

                    // for some strange reason, when a NumberField's value is set to 0, the getvalue() method returns ""
                    if ((string)newValues["UnitPrice"] == "") newValues["UnitPrice"] = 0;
                    if ((string)newValues["UnitsInStock"] == "") newValues["UnitsInStock"] = 0;
                    if ((string)newValues["UnitsOnOrder"] == "") newValues["UnitsOnOrder"] = 0;
                    if ((string)newValues["ReorderLevel"] == "") newValues["ReorderLevel"] = 0;
                    fireEvent("updated", this, true, newValues);
                })
            ));
        }

    }

    public class ProductsDetailsFormEvents {
        /// <summary>Fires when a new product is inserted
        /// <pre><code>
        /// USAGE: ({bool} success)
        /// </code></pre>
        /// <list type="bullet">
        /// <item><term><b>success</b></term><description>true, if the insert was successful</description></item>
        /// </list>
        /// </summary>
        public static string inserted { get { return "inserted"; } }
        /// <summary>Fires when a product is updated
        /// <pre><code>
        /// USAGE: ({bool} success, {Dictionary} newValues)
        /// </code></pre>
        /// <list type="bullet">
        /// <item><term><b>success</b></term><description>true, if the update was successful</description></item>
        /// <item><term><b>newValues</b></term><description>the new values entered into the form</description></item>
        /// </list>
        /// </summary>
        public static string updated { get { return "updated"; } }
    }

    public delegate void ProductsDetailsFormInsertedDelegate(ProductDetailsForm form, bool success);
    public delegate void ProductsDetailsFormUpdatedDelegate(ProductDetailsForm form, bool success, Dictionary newValues);
}
